﻿using Abp.Application.Services.Dto;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.Linq.Extensions;
using Abp.UI;
using Camc.Quality.Bop;
using Camc.Quality.Bop.Dto;
using Camc.Quality.Bop.TreeObject;
using Camc.Quality.Common;
using Camc.Quality.IOperationHistory;
using Camc.Quality.Quality;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Camc.Quality.ProductionPlan
{
    /// <summary>
    /// 生产任务
    /// </summary>
    public class MakeTaskAppService : QualityAppServiceBase
    {
        private readonly IRepository<MakeTask, Guid> _makeTaskRepository;
        private readonly IOperationHistoryAppService _iOperationHistoryAppService;
        private readonly IRepository<BopNode, Guid> _bopNodeRepository;
        private readonly IRepository<BopDesc, Guid> _bopDescRepository;
        private readonly IRepository<ProcessesEntity, Guid> _processesEntityRepository;
        private readonly IRepository<WorkStepEntity, Guid> _workStepEntityRepository;
        private readonly IRepository<ProductionScheduler, Guid> _productionSchedulerRepository;
        private readonly BopNodeAppService _bopNodeAppService;
    
        public MakeTaskAppService(IRepository<MakeTask, Guid> makeTaskRepository, 
            IOperationHistoryAppService iOperationHistoryAppService,
            IRepository<BopNode, Guid> bopNodeRepository,
            IRepository<BopDesc, Guid> bopDescRepository,
            IRepository<ProductionScheduler, Guid> productionSchedulerRepository,
            IRepository<WorkStepEntity, Guid> workStepEntityRepository,
            IRepository<ProcessesEntity, Guid> processesEntityRepository,
            BopNodeAppService bopNodeAppService
            )
        {
            _makeTaskRepository = makeTaskRepository;
            _iOperationHistoryAppService = iOperationHistoryAppService;
            _bopNodeRepository = bopNodeRepository;
            _bopDescRepository = bopDescRepository;
            _productionSchedulerRepository = productionSchedulerRepository;
            _workStepEntityRepository = workStepEntityRepository;
            _processesEntityRepository = processesEntityRepository;
            _bopNodeAppService = bopNodeAppService;
           
        }

        /// <summary>
        /// 插入或者更新生产任务
        /// </summary>
        /// <param name="input"></param>
        public ResultMessage InsertOrUpdateMakeTask(MakeTaskInput input)
        {
            ResultMessage resultMessage = new ResultMessage();
            try
            {
                if (string.IsNullOrWhiteSpace(input.DrawingNo))
                {
                    resultMessage.code = 1;
                    resultMessage.Message = "产品图号格式不正确!";
                    return resultMessage;
                    //throw new UserFriendlyException("产品图号格式不正确!");
                }
                if (string.IsNullOrWhiteSpace(input.ProductName))
                {
                    resultMessage.code = 1;
                    resultMessage.Message = "产品名称格式不正确!";
                    return resultMessage;
                    //throw new UserFriendlyException("产品名称格式不正确!");
                }
                if (string.IsNullOrWhiteSpace(input.Remark))
                {
                    resultMessage.code = 1;
                    resultMessage.Message = "原因或依据格式不正确!";
                    return resultMessage;
                    //throw new UserFriendlyException("原因或依据格式不正确!");
                }
                var temp = ObjectMapper.Map<MakeTask>(input);
                if (temp.Id == Guid.Empty)
                {
                    var tempTask = _makeTaskRepository.GetAll().Where(d => d.ModelId == input.ModelId && d.LotNoId == input.LotNoId).FirstOrDefault();
                    if (tempTask != null)
                    {
                        resultMessage.code = 1;
                        resultMessage.Message = "已存在该型号和发次下的生产任务!";
                        return resultMessage;
                        //throw new UserFriendlyException("已存在该型号和发次下的生产任务!");
                    }
                    temp.AssignmentAuthor = GetCurrentUser().Surname + GetCurrentUser().Name;
                    temp.AssignmentTime = DateTime.Now.ToString();
                    temp.ProductingStatus = ProductingStatus.已创建;
                    var guid = _makeTaskRepository.InsertAndGetId(temp);
                    _iOperationHistoryAppService.InsertOperationLog(guid, 10, 14, "新增火箭生产任务:" + input.JobNumber + "信息");
                }
                else
                {
                    var data = _makeTaskRepository.GetAll().Where(d => d.Id == input.Id.Value).AsNoTracking().FirstOrDefault();
                    var bopDesc = _bopDescRepository.GetAll().Where(d => d.ModelId == data.ModelId && d.LotNoId == data.LotNoId).FirstOrDefault();
                    if (bopDesc != null)
                    {
                        if (bopDesc.Model != input.Model || bopDesc.LotNo != input.LotNo)
                        {
                            resultMessage.code = 1;
                            resultMessage.Message = "该生产任务已存在Bop不可修改!";
                            return resultMessage;

                        }
                    
                    }


                    temp.AssignmentAuthor = data.AssignmentAuthor;
                    temp.AssignmentTime = data.AssignmentTime;
                    temp.ProductingStatus = data.ProductingStatus;
                    _makeTaskRepository.Update(temp);
                    _iOperationHistoryAppService.InsertOperationLog(input.Id.Value, 10, 15, "修改" + input.JobNumber + "信息");
                }
                resultMessage.code = 0;
                return resultMessage;
            }
            catch (Exception ex)
            {
                resultMessage.code = 1;
                resultMessage.Message = ex.Message;
                return resultMessage;
            }
        }
       /// <summary>
       /// 查询生产任务
       /// </summary>
       /// <param name="input"></param>
       /// <returns></returns>
        public PagedResultDto<ProductionTaskOutput> GetAssignments(AssignmentSelectInput input)
        {
            var query = _makeTaskRepository.GetAll().WhereIf(input.Id != null, item => item.Id == input.Id)
                .WhereIf(input.ModelId!=null, item => item.ModelId==input.ModelId)
                .WhereIf(input.LotNoId != null, item => item.LotNoId == input.LotNoId)
                .WhereIf(!input.JobNumber.IsNullOrWhiteSpace(), item => item.JobNumber.Contains(input.JobNumber));
            int count = query.Count();
            List<ProductionTaskOutput> temp = new List<ProductionTaskOutput>();
            if (query.Count() > 0)
            {
                query = query.OrderByDescending(d => d.CreationTime).PageBy(input);
                temp = ObjectMapper.Map<List<ProductionTaskOutput>>(query);
                foreach (var item in temp)
                {
                    var bopDesc = _bopDescRepository.GetAll().Where(d => d.LotNoId == item.LotNoId && d.ModelId == item.ModelId).FirstOrDefault();
                    if (bopDesc != null)
                    { 
                        if (bopDesc.WorkingHourStatus == "0")//工序任务
                        {
                            var node = _bopNodeRepository.GetAll().Where(d => d.BopDescId == bopDesc.Id && d.TechniqueEntityId != null).ToList();
                            if (node.Count > 0)
                            {
                                var techList = node.Select(d => d.TechniqueEntityId);

                                var processes = from cc in _processesEntityRepository.GetAll()
                                                join mm in techList on cc.TechniqueEntityId equals mm
                                                select new StatisticsHour
                                                {
                                                    Id = cc.Id,
                                                    Hour = cc.ProcessesWorking,
                                                };
                                if (processes.Count() > 0)
                                {
                                    decimal proTempCount = Convert.ToDecimal(processes.Count());

                                    var proFinish = (from cc in processes
                                                     join mm in _productionSchedulerRepository.GetAll() on cc.Id equals mm.NodeId
                                                     where mm.ProductingStatus == ProductingStatus.已完成
                                                     select new StatisticsHour
                                                     {
                                                         Id = cc.Id,
                                                         Hour = cc.Hour,
                                                     }).ToList();
                                    var finishIds = proFinish.Select(d => d.Id);
                                    var processesIds = processes.Select(d => d.Id);
                                    var leftIds = processesIds.Except(finishIds).ToArray();

                                    for (int i = 0; i < leftIds.Length; i++)
                                    {
                                        var workList = from cc in _workStepEntityRepository.GetAll().Where(d => d.ProcessesEntityId == leftIds[i])
                                                       select new
                                                       {
                                                           Id = cc.Id,
                                                       };
                                        var workFinish = from cc in workList
                                                         join mm in _productionSchedulerRepository.GetAll() on cc.Id equals mm.NodeId
                                                         where mm.ProductingStatus == ProductingStatus.已完成
                                                         select cc;
                                        var workCount = workList.Count();
                                        var workFinishCount = workFinish.Count();
                                        if (workCount == workFinishCount)
                                        {
                                            var tempHour = processes.Where(d => d.Id == leftIds[i]).First().Hour;
                                            StatisticsHour hour = new StatisticsHour();
                                            hour.Id = leftIds[i];
                                            hour.Hour = tempHour;
                                            proFinish.Add(hour);
                                        }
                                    }
                                    var completeCount = proFinish.Count();

                                    if (proTempCount != 0)
                                    {
                                        item.StepCompletionSchedule = (decimal)completeCount / proTempCount;
                                    }
                                   
                                    var completeHour = proFinish.Sum(d => d.Hour);
                                    var proTempHour = processes.Sum(d => d.Hour);
                                    if (proTempHour != 0)
                                    {
                                        item.HourCompletionSchedule = (decimal)completeHour / proTempHour;
                                    }
                                    
                                }
                                else
                                {
                                    item.StepCompletionSchedule = 0;
                                    item.HourCompletionSchedule = 0;
                                }
                            }
                            else
                            {
                                item.StepCompletionSchedule = 0;
                                item.HourCompletionSchedule = 0;
                            }

                        }
                        else if (bopDesc.WorkingHourStatus == "1")//工步任务
                        {
                            var node = _bopNodeRepository.GetAll().Where(d => d.BopDescId == bopDesc.Id && d.TechniqueEntityId != null).ToList();
                            if (node.Count > 0)
                            {
                                List<StatisticsHour> hours = new List<StatisticsHour>();
                                var techList = node.Select(d => d.TechniqueEntityId);

                                var totalWork = from cc in _workStepEntityRepository.GetAll()
                                                join mm in techList on cc.TechniqueEntityId equals mm
                                                select new StatisticsHour { Id = cc.Id, Hour = cc.WorkStepWorking };


                                var workSteps = (from cc in _processesEntityRepository.GetAll()
                                                 join mm in techList on cc.TechniqueEntityId equals mm
                                                 join ff in _productionSchedulerRepository.GetAll() on cc.Id equals ff.NodeId
                                                 join pp in _workStepEntityRepository.GetAll() on cc.Id equals pp.ProcessesEntityId
                                                 where ff.ProductingStatus == ProductingStatus.已完成
                                                 select new StatisticsHour { Id = pp.Id, Hour = pp.WorkStepWorking }).ToList();
                                var workFinish = (from cc in totalWork
                                                  join ff in _productionSchedulerRepository.GetAll() on cc.Id equals ff.NodeId
                                                  where ff.ProductingStatus == ProductingStatus.已完成
                                                  select new StatisticsHour { Id = cc.Id, Hour = cc.Hour }).ToList();

                                if (workSteps.Count > 0)
                                {
                                    hours.AddRange(workSteps);
                                }
                                if (workFinish.Count > 0)
                                {
                                    hours.AddRange(workFinish);
                                }

                                if (hours.Count() > 0)
                                {

                                    var completeCount = hours.Count;
                                    decimal workTempCount = totalWork.Count();
                                    if (workTempCount != 0)
                                    {
                                        item.StepCompletionSchedule = (decimal)completeCount / workTempCount;
                                    }
                                 
                                    var completeHour = hours.Sum(d => d.Hour);
                                    var workTempHour = totalWork.Sum(d => d.Hour);
                                    if (workTempCount != 0)
                                    {
                                        item.HourCompletionSchedule = (decimal)completeCount / workTempCount;
                                    }
                                   
                                }
                                else
                                {
                                    item.StepCompletionSchedule = 0;
                                    item.HourCompletionSchedule = 0;
                                }
                            }
                            else
                            {
                                item.StepCompletionSchedule = 0;
                                item.HourCompletionSchedule = 0;
                            }

                        }
                        else
                        {
                            item.StepCompletionSchedule = 0;
                            item.HourCompletionSchedule = 0;
                        }

                    }
                }
            }
            return new PagedResultDto<ProductionTaskOutput>(count, temp);
        }

        /// <summary>
        /// 根据型号发次获取装配任务号
        /// </summary>
        /// <param name="LotNoId">发次Id</param>
        /// <param name="ModelId">型号Id</param>
        /// <returns></returns>
        public MakeJobTask GetJobNumber(Guid LotNoId, Guid ModelId)
        {
            MakeJobTask makeJob = new MakeJobTask();
            string jobNumStr = "";
            var makeTask=  _makeTaskRepository.GetAll().Where(d => d.ModelId == ModelId && d.LotNoId == LotNoId).FirstOrDefault();
            if (makeTask != null)
            {
                makeJob.DrawingNo = makeTask.DrawingNo;
                makeJob.ProductName = makeTask.ProductName;
                makeJob.JobNumber = makeTask.JobNumber;
                makeJob.StoreId = makeTask.StoreId;
            }
            return makeJob;
        }
        private class SchedulerData
        {

            public Guid NodeId { get; set; }

            public DateTime? StartTime { get; set; }

            public DateTime? EndTime { get; set; }

            public decimal WorkHour { get; set; }

            /// <summary>
            /// 装配班组
            /// </summary>
            public string OrganizationUnitId { get; set; }
            /// <summary>
            /// 装配班组描述
            /// </summary>
            public string OrganizationUnitDesc { get; set; }
            /// <summary>
            /// 状态
            /// </summary>
            public ProductingStatus? ProductingStatus { get; set; }

            /// <summary>
            ///装配人员
            /// </summary>
            public string UserId { get; set; }

            ///// <summary>
            ///// 装配人员描述
            ///// </summary>
            //public string UserName { get; set; }
        }

        private class StatisticsHour
        {
            public Guid Id { get; set; }

            public decimal Hour { get; set; }
        }
        /// <summary>
        /// 导出计划
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public ResultMessage GetPlanBatchExportJson(BopExportInput input)
        {
            ResultMessage resultMessage = new ResultMessage();
            try
            {
                BopExportput bopExportput = new BopExportput();
                BopTreeJson bopTree = new BopTreeJson();
                long edution = 0;
                bopTree = _bopNodeAppService.GetBopTreeJson(input.ModelId, input.LotNoId,ref edution);

                if (input.TechIdList==null)
                {
                    resultMessage.code = 1;
                    resultMessage.Message = "请先选择要导出的计划";
                    return resultMessage;
                    //throw new UserFriendlyException("请先选择要导出的计划!");
                }
                if (bopTree != null)
                {
                    String DateStr = System.DateTime.Now.ToString("yyyyMMddHHmm");
                    var tempDesc = _bopDescRepository.FirstOrDefault(d => d.ModelId == input.ModelId && d.LotNoId == input.LotNoId);
                    string treePath = "../../Bop/BopPlan/" + DateStr + "/" + tempDesc.Model +"_"+ tempDesc.LotNo + "/";
                    if (!Directory.Exists(treePath))
                    {
                        Directory.CreateDirectory(treePath);
                    }
                    string treefp = treePath + tempDesc.Model + "_" + tempDesc.LotNo + ".json"; //"_" +System.DateTime.Now.ToString("yyyyMMddHHmm")
                    if (File.Exists(treefp))  // 判断是否已有相同文件 
                    {
                        File.Delete(treefp);
                    }
                    var treeJson = Newtonsoft.Json.JsonConvert.SerializeObject(bopTree);
                    File.WriteAllText(treefp, treeJson);

                    var bopDesc = _bopDescRepository.GetAll().Where(d => d.ModelId == input.ModelId && d.LotNoId == input.LotNoId).FirstOrDefault();
                    if (bopDesc != null)
                    {
                        var bopNodeList = _bopNodeRepository.GetAll().Where(d => d.BopDescId == bopDesc.Id).ToList();

                        var schedulers = (from cc in _productionSchedulerRepository.GetAll()
                                     join mm in bopNodeList.Distinct() on cc.NodeId equals mm.Id
                                     select new SchedulerData
                                     {
                                         NodeId = mm.Id,
                                         StartTime = cc.StartTime,
                                         EndTime = cc.EndTime,
                                         OrganizationUnitId=cc.OrganizationUnitId,
                                         OrganizationUnitDesc=cc.OrganizationUnitDesc,
                                         WorkHour=mm.WorkingHour,
                                         ProductingStatus=cc.ProductingStatus,
                                         //UserId=cc.UserId,
                                         //UserName=cc.UserName

                                     }).ToList();
                        List<SchedulerData> query = new List<SchedulerData>();
                        for (int i = 0; i < bopNodeList.Count; i++)
                        {
                            int index = schedulers.FindIndex(d => d.NodeId == bopNodeList[i].Id);
                            if (index != -1)
                            {
                                query.Add(schedulers[index]);
                            }
                            else
                            {
                                SchedulerData scheduler = new SchedulerData();
                                scheduler.NodeId = bopNodeList[i].Id;
                                scheduler.WorkHour = bopNodeList[i].WorkingHour;
                                query.Add(scheduler);
                            }
                            if (bopNodeList[i].TechniqueEntityId != null)
                            {
                                index = input.TechIdList.FindIndex(d => d == bopNodeList[i].TechniqueEntityId);
                                if (index != -1|| bopNodeList[i].PlanExprot==true)
                                {

                                    if (false == bopNodeList[i].BopExprot)
                                    {
                                        resultMessage.code = 1;
                                        resultMessage.Message = bopNodeList[i].ProcessCode + "该规程没有Bop导出！";
                                        return resultMessage;
                                    }
                                    else
                                    {
                                        if (index != -1)
                                        {
                                            bopNodeList[i].PlanExprot = true;
                                            _bopNodeRepository.Update(bopNodeList[i]);
                                        }
                                    }
                                    var processList = _processesEntityRepository.GetAll().Where(d => d.TechniqueEntityId == bopNodeList[i].TechniqueEntityId).ToList();
                                    for (int j = 0; j < processList.Count; j++)
                                    {
                                        var tempSche = _productionSchedulerRepository.GetAll().Where(d => d.NodeId == processList[j].Id).FirstOrDefault();
                                        SchedulerData scheduler = new SchedulerData();
                                        scheduler.NodeId = processList[j].Id;
                                        scheduler.WorkHour = processList[j].ProcessesWorking;
                                        if (tempSche != null)
                                        {
                                            //scheduler.OrganizationUnitId = tempSche.OrganizationUnitId;
                                            //scheduler.OrganizationUnitDesc = tempSche.OrganizationUnitDesc;
                                            scheduler.StartTime = tempSche.StartTime;
                                            scheduler.EndTime = tempSche.EndTime;
                                            scheduler.ProductingStatus = tempSche.ProductingStatus;
                                            //scheduler.UserId = tempSche.UserId;
                                            //scheduler.UserName = tempSche.UserName;
                                          
                                        }
                                        query.Add(scheduler);
                                        var workList = _workStepEntityRepository.GetAll().Where(d => d.ProcessesEntityId == processList[j].Id).ToList();
                                        foreach (var item in workList)
                                        {
                                            SchedulerData workTempSche = new SchedulerData();
                                            workTempSche.NodeId = item.Id;
                                            workTempSche.WorkHour = item.WorkStepWorking;
                                            var tempOne = _productionSchedulerRepository.GetAll().Where(d => d.NodeId == item.Id).FirstOrDefault();
                                            if (tempOne != null)
                                            {
                                                //workTempSche.OrganizationUnitId = tempOne.OrganizationUnitId;
                                                //workTempSche.OrganizationUnitDesc = tempOne.OrganizationUnitDesc;
                                                workTempSche.StartTime = tempOne.StartTime;
                                                workTempSche.EndTime = tempOne.EndTime;
                                                workTempSche.ProductingStatus = tempOne.ProductingStatus;
                                                //workTempSche.UserId = tempOne.UserId;
                                                //workTempSche.UserName = tempOne.UserName;
                                            }
                                            query.Add(workTempSche);
                                        }
                                    }
                                }
                            }
                        }



                        //var techNodeList = from tc in _bopNodeRepository.GetAll()
                        //                   join mm in input.TechIdList on tc.TechniqueEntityId equals mm
                        //                   select tc;
                        //if (techNodeList.Count() > 0)
                        //{
                        //    foreach (var item in techNodeList)
                        //    {
                        //        item.PlanExprot = true;
                        //        _bopNodeRepository.Update(item);
                        //    }
                        //    bopNodeList.AddRange(techNodeList.Select(d => d.Id));
                        //}


                        var makeTemp = _makeTaskRepository.GetAll().Where(d => d.ModelId == input.ModelId && d.LotNoId == input.LotNoId).FirstOrDefault();
                        SchedulerData data = new SchedulerData();
                        data.NodeId = bopDesc.Id;
                        data.StartTime = makeTemp.StartTime;
                        data.EndTime = makeTemp.EndDate;
                        query.Add(data);
                        if (query.Count > 0)
                        {
                            string planPath = "../../Bop/BopPlan/" + DateStr + "/" + tempDesc.Model + "_" + tempDesc.LotNo + "/Plan/";

                            if (!Directory.Exists(planPath))
                            {
                                Directory.CreateDirectory(planPath);
                            }
                            string fp = planPath + "plan.json"; //"_" +System.DateTime.Now.ToString("yyyyMMddHHmm")
                            if (File.Exists(fp))  // 判断是否已有相同文件 
                            {
                                File.Delete(fp);
                            }
                            var listjson = Newtonsoft.Json.JsonConvert.SerializeObject(query);
                            File.WriteAllText(fp, listjson);

                            string fileSavePath = Environment.CurrentDirectory + "/wwwroot/Zip/BopPlan/" + DateStr + "/" + tempDesc.Model + "_" + tempDesc.LotNo + "/";
                            if (!Directory.Exists(fileSavePath))
                            {
                                Directory.CreateDirectory(fileSavePath);
                            }
                            string zipTreeName = fileSavePath + tempDesc.Model + "_" + tempDesc.LotNo + "_"+ edution.ToString() +".zip";
                            if (File.Exists(zipTreeName))
                            {
                                File.Delete(zipTreeName);
                            }
                            ZipFile.CreateFromDirectory(treePath, zipTreeName);
                            resultMessage.code = 0;
                            resultMessage.Message = ConfigHelper.GetAppSetting("App", "GetAppUrl") + "/Zip/BopPlan/" + DateStr + "/" + tempDesc.Model + "_" + tempDesc.LotNo + "/" + tempDesc.Model + "_" + tempDesc.LotNo+ "_" + edution.ToString() + ".zip";
                            return resultMessage;
                            //return ConfigHelper.GetAppSetting("App", "GetAppUrl") + "/Zip/BopPlan/" + DateStr + "/" + tempDesc.Model + tempDesc.LotNo + "/" + tempDesc.Model + tempDesc.LotNo + ".zip";
                        }
                        else
                        {
                            resultMessage.code = 1;
                            resultMessage.Message = "";
                            return resultMessage;
                        }
                    }
                    else
                    {
                        resultMessage.code = 1;
                        resultMessage.Message = "";
                        return resultMessage;
                    }

                }
                else
                {
                    resultMessage.code = 1;
                    resultMessage.Message = "";
                    return resultMessage;
                    //return "";
                }
            }
            catch (Exception ex)
            {
                resultMessage.code = 1;
                resultMessage.Message = ex.Message;
                return resultMessage;
            }
        }
    }
}
 